/**
  ******************************************************************************
  * @file    timer_software.c
  * @author  ashuai0110
  * @version V2.1
  * @date    2023-09-26
  * @brief   软件定时器
  *
  ******************************************************************************
  * @attention
  *
  * 版权声明:内容为编者(ashuai0110)原创,使用请注明出处,当然,你也可以不这样做^_^
  * 出处链接:https://gitee.com/ashuai0110/mcu_reuse_development_module.git
  *
  ******************************************************************************
  */

/* 包含头文件-----------------------------------------------------------------*/
#include "timer_software.h"

/**
 * @addtogroup modules
 * @{
 */

/**
 * @defgroup timer_software timer_software
 * @{
 */

/* 私有宏定义-----------------------------------------------------------------*/
/**
 * @defgroup timer_software_local_macros timer software local macros
 * @{
 */

/**
 * @defgroup timer_software_check_parameters_validity timer software check parameters validity
 * @{
 */
/* 软件定时器运行标志有效性检查 */
#define IS_VALID_TIMER_RUN(x)                                                  \
(       ((x) == TIMER_RUN_START)          ||                                   \
        ((x) == TIMER_RUN_STOP))
/**
 * @}
 */

/**
 * @}
 */

/* 私有类型定义---------------------------------------------------------------*/

/* 私有变量-------------------------------------------------------------------*/
/**
 * @defgroup timer_software_local_variables timer software local variables
 * @{
 */

static timer_s_t *pTimerTaskHead = NULL; /*!< 软件定时器工作链表头节点 */

/**
 * @}
 */

/* 全局变量-------------------------------------------------------------------*/

/* 私有函数原型---------------------------------------------------------------*/

/**
 * @defgroup timer_software_global_functions timer software global functions
 * @{
 */

/**
  * @brief  软件定时器任务初始化
  *
  * @note   创建后的任务默认加入到工作链表中(如需挂起请使用timer_s_pending)
  *
  * @param  _ts             : 软件定时器任务实例
  *
  * @param  targetTicks     : 目标计数值 例如定时任务为500ms,调度器周期10ms,则targetTicks=500ms/10ms=50
  *
  * @param  callbackFn      : 回调函数
  *
  * @param  runFlg          : 运行标志 @ref timer_run_flg
  *   @arg  TIMER_RUN_STOP  : 不运行
  *   @arg  TIMER_RUN_START : 运行
  *
  * @retval uint8_t
  *    @arg RET_OK          : 成功
  *    @arg RET_ERR         : 已存在(已被插入)
  */
uint8_t timer_s_init(timer_s_t *_ts, uint32_t targetTicks, void (* callbackFn)(void), uint8_t runFlg)
{
    ASSERT_PARAM(IS_VALID_POINT(_ts));
    ASSERT_PARAM(IS_VALID_POINT(callbackFn));
    ASSERT_PARAM(IS_VALID_TIMER_RUN(runFlg));
    
    _ts->curTicks = 0;
    _ts->targetTicks = targetTicks;
    _ts->callbackFn = callbackFn;
    _ts->runFlg = runFlg;
    
    return timer_s_insert(_ts);
}

/**
  * @brief  软件定时器任务取消初始化
  *
  * @param  _ts : 软件定时器任务实例
  *
  * @retval None
  */
void timer_s_de_init(timer_s_t *_ts)
{
    ASSERT_PARAM(IS_VALID_POINT(_ts));
    
    timer_s_pending(_ts);
    memset(_ts, 0, sizeof(timer_s_t));
}

/**
  * @brief  软件定时器任务插入(插入工作链表)
  *
  * @param  _ts     : 软件定时器任务实例
  *
  * @retval uint8_t
  *    @arg RET_OK  : 成功
  *    @arg RET_ERR : 已存在(已被插入)
  */
uint8_t timer_s_insert(timer_s_t *_ts)
{
    timer_s_t *tsTarget = pTimerTaskHead;
    
    ASSERT_PARAM(IS_VALID_POINT(_ts));
    
    while(tsTarget)
    {
        if(tsTarget == _ts) { return RET_ERR; }
        tsTarget = tsTarget->pNext;
    }
    _ts->pNext = pTimerTaskHead;
    pTimerTaskHead = _ts;
    
    return RET_OK;
}

/**
  * @brief  软件定时器任务挂起(从工作链表中取下)
  *
  * @param  _ts     : 软件定时器任务实例
  *
  * @retval uint8_t
  *    @arg RET_OK  : 成功
  *    @arg RET_ERR : 不存在(已被挂起)
  */
uint8_t timer_s_pending(timer_s_t *_ts)
{
    timer_s_t *tsTarget = pTimerTaskHead;
    timer_s_t *tsLast = NULL;
    
    ASSERT_PARAM(IS_VALID_POINT(_ts));
    
    while(tsTarget)
    {
        /* 查找任务是否存在 */
        if(tsTarget == _ts)
        {
            /* 是否在头节点 */
            if(NULL == tsLast)
            {
                /* 在头节点则将下一个节点作为新的头节点 */
                pTimerTaskHead = tsTarget->pNext;
            }
            else
            {
                /* 不在头节点则将下一个节点链接到上一个节点 */
                tsLast->pNext = tsTarget->pNext;
                pTimerTaskHead = tsLast;
            }
            
            return RET_OK;
        }
        tsLast = tsTarget;
        tsTarget = tsTarget->pNext;
    }
    
    return RET_ERR;
}

/**
  * @brief  软件定时器任务轮询处理
  *
  * @note   此函数执行周期即是软件定时器任务计数值累加周期
  *
  * @param  None
  *
  * @retval None
  */
void timer_s_poll(void)
{
    timer_s_t *tsTarget;
    
    for(tsTarget = pTimerTaskHead; tsTarget; tsTarget = tsTarget->pNext)
    {
        if(TIMER_RUN_START == tsTarget->runFlg)
        {
            if(tsTarget->curTicks < tsTarget->targetTicks)
            {
                tsTarget->curTicks++;
            }
            else
            {
                tsTarget->callbackFn();
                tsTarget->curTicks = 0;
            }
        }
    }
}

/**
  * @brief  设置软件定时器任务的当前计数值
  *
  * @param  _ts      : 软件定时器任务实例
  *
  * @param  curTicks : 当前计数值
  *
  * @retval None
  */
void timer_s_set_cur_ticks(timer_s_t *_ts, uint32_t curTicks)
{
    ASSERT_PARAM(IS_VALID_POINT(_ts));
    
    _ts->curTicks = curTicks;
}

/**
  * @brief  获取软件定时器任务的当前计数值
  *
  * @param  _ts : 软件定时器任务实例
  *
  * @retval 当前计数值
  */
uint32_t timer_s_get_cur_ticks(timer_s_t *_ts)
{
    ASSERT_PARAM(IS_VALID_POINT(_ts));
    
    return _ts->curTicks;
}

/**
  * @brief  设置软件定时器任务的目标计数值
  *
  * @param  _ts         : 软件定时器任务实例
  *
  * @param  targetTicks : 目标计数值
  *
  * @retval None
  */
void timer_s_set_target_ticks(timer_s_t *_ts, uint32_t targetTicks)
{
    ASSERT_PARAM(IS_VALID_POINT(_ts));
    
    _ts->targetTicks = targetTicks;
}

/**
  * @brief  获取软件定时器任务的目标计数值
  *
  * @param  _ts : 软件定时器任务实例
  *
  * @retval 目标计数值
  */
uint32_t timer_s_get_target_ticks(timer_s_t *_ts)
{
    ASSERT_PARAM(IS_VALID_POINT(_ts));
    
    return _ts->targetTicks;
}

/**
  * @brief  设置软件定时器任务的运行标志
  *
  * @param  _ts             : 软件定时器任务实例
  *
  * @param  runFlg          : 运行标志 @ref timer_run_flg
  *   @arg  TIMER_RUN_STOP  : 不运行
  *   @arg  TIMER_RUN_START : 运行
  *
  * @retval None
  */
void timer_s_set_run(timer_s_t *_ts, uint8_t runFlg)
{
    ASSERT_PARAM(IS_VALID_POINT(_ts));
    ASSERT_PARAM(IS_VALID_TIMER_RUN(runFlg));
    
    _ts->runFlg = runFlg;
}

/**
  * @brief  获取软件定时器任务的运行标志
  *
  * @param  _ts             : 软件定时器任务实例
  *
  * @retval uint8_t         : 运行标志 @ref timer_run_flg
  *    @arg TIMER_RUN_STOP  : 不运行
  *    @arg TIMER_RUN_START : 运行
  */
uint8_t timer_s_get_run(timer_s_t *_ts)
{
    ASSERT_PARAM(IS_VALID_POINT(_ts));
    
    return _ts->runFlg;
}

/**
 * @}
 */

/**
 * @}
 */

/**
 * @}
 */
